#include "shared_image_queue.hpp"
#include <stdint.h>

using namespace boost::interprocess;

CSharedImageQueueWriter::CSharedImageQueueWriter()
{

}

CSharedImageQueueWriter::~CSharedImageQueueWriter()
{
        close();
        shared_memory_object::remove(str_shared_memory_name_.c_str());
}

bool CSharedImageQueueWriter::init(std::string str_shared_memory_name,
        int image_width, int image_height)
{
        shared_memory_object::remove(str_shared_memory_name_.c_str());

        str_shared_memory_name_ = str_shared_memory_name;
        shm_ = shared_memory_object(open_or_create, str_shared_memory_name.c_str(), read_write);
        image_size_ = image_width * image_height * 3;
        meta_ = SMappedRegionMeta(1, image_width, image_height, 50, 0);
        shm_.truncate(sizeof(SMappedRegionMeta)+image_size_ * meta_.image_array_size_);
        region_ = mapped_region(shm_, read_write);
        std::memcpy(region_.get_address(), &meta_, sizeof(SMappedRegionMeta));
        return true;
}

void CSharedImageQueueWriter::write(const unsigned char* pimage_data, int image_size)
{
        assert(image_size_ == image_size);
        int64_t write_pos = sizeof(SMappedRegionMeta)+ 
                (int64_t)(meta_.written_index_ % meta_.image_array_size_) * image_size_;
        std::memcpy((unsigned char*)region_.get_address() + write_pos,
                pimage_data, image_size);
        meta_.written_index_ += 1;
        std::memcpy(region_.get_address(), &meta_, sizeof(SMappedRegionMeta));
}

void CSharedImageQueueWriter::close()
{
        meta_.status_ = 0;
        std::memcpy(region_.get_address(), &meta_, sizeof(SMappedRegionMeta));
}

CSharedImageQueueReader::CSharedImageQueueReader()
{

}

CSharedImageQueueReader::~CSharedImageQueueReader()
{
        //shared_memory_object::remove(str_shared_memory_name_.c_str());
}

bool CSharedImageQueueReader::init(std::string str_shared_memory_name)
{
        str_shared_memory_name_ = str_shared_memory_name;
        // if shared memory dose not exist, boost throw an exception
        try {
                shm_ = shared_memory_object(open_only, str_shared_memory_name.c_str(), read_only);
        }
        catch (...) {
                return false;
        }
        region_ = mapped_region(shm_, read_only);
        std::memcpy(&meta_, region_.get_address(), sizeof(SMappedRegionMeta)); 
        image_size_ = meta_.image_width_ * meta_.image_height_ * 3;
        return true;
}

void CSharedImageQueueReader::get_image_size(int &image_width, int &image_height)
{
        std::memcpy(&meta_, region_.get_address(), sizeof(SMappedRegionMeta));
        image_width = meta_.image_width_;
        image_height = meta_.image_height_;
}

unsigned int CSharedImageQueueReader::get_current_written_index()
{
        std::memcpy(&meta_, region_.get_address(), sizeof(SMappedRegionMeta));
        return meta_.written_index_;
}

int CSharedImageQueueReader::read( char* pimage_data, int image_size, unsigned int read_index)
{
        assert(image_size_ == image_size);
        std::memcpy(&meta_, region_.get_address(), sizeof(SMappedRegionMeta));
        if (meta_.status_ == 0) return -1;
        if (read_index >= meta_.written_index_) return 0;
        int64_t read_pos = sizeof(SMappedRegionMeta)+
                (int64_t)(read_index % meta_.image_array_size_) * image_size;
        std::memcpy(pimage_data, (unsigned char*)region_.get_address() + read_pos,
                image_size);
        return 1;
}